package org.ramoths.netcom.sessions;

import org.ramoths.netcom.sessions.verrous.VrEcritureOutputStream;

import java.io.OutputStream;

public class ThOutputStreamEnvoye extends Thread
{
	private final SessionCommunication sessionComm;
	private final int idOutputStream;
	private final OutputStream outputStream;
	//
	private final VrEcritureOutputStream vrEcritureOutputStream;
	private boolean demandeEcriture;
	private byte[] donneesAEcrire;
	//
	private final SuiviFlux suiviFlux;
	
	public ThOutputStreamEnvoye(SessionCommunication sessionComm, int idInputStream, OutputStream outputStream, SuiviFlux vrFlux)
	{
		super.setDaemon(true);
		super.setName("TH-OUTPUTSTREAM-ENVOYE");
		super.setPriority(NORM_PRIORITY);
		//
		this.sessionComm = sessionComm;
		this.idOutputStream = idInputStream;
		this.outputStream = outputStream;
		//
		this.vrEcritureOutputStream = new VrEcritureOutputStream();
		this.demandeEcriture = false;
		this.donneesAEcrire = null;
		//
		this.suiviFlux = vrFlux;
	}
	
	public void ecrire(byte[] donnees)
	{
		vrEcritureOutputStream.lock();
		try
		{
			demandeEcriture = true;
			donneesAEcrire = donnees;
			vrEcritureOutputStream.getConditionDemandeEcriture().signal();
		}
		finally
		{
			vrEcritureOutputStream.unlock();
		}
	}
	
	@Override
	public void run()
	{
		while (true)
		{
			vrEcritureOutputStream.lock();
			try
			{
				try
				{
					while (!demandeEcriture)
						vrEcritureOutputStream.getConditionDemandeEcriture().await();
				}
				catch (InterruptedException ex)
				{
					suiviFlux.setFinFlux(new Exception("Flux interrompu!"));
					break;
				}
				demandeEcriture = false;
				//
				if (donneesAEcrire == null)
				{
					try
					{
						outputStream.close();
					}
					catch (Exception ex)
					{
						sessionComm.oseEnvoyerFinException(idOutputStream, ex);
						suiviFlux.setFinFlux(ex);
						break;
					}
					sessionComm.oseEnvoyerFin(idOutputStream);
					suiviFlux.setFinFlux(null);
					break;
				}
				//
				try
				{
					outputStream.write(donneesAEcrire);
				}
				catch (Exception ex)
				{
					sessionComm.oseEnvoyerFinException(idOutputStream, ex);
					suiviFlux.setFinFlux(ex);
					break;
				}
				sessionComm.oseEnvoyerNotifPortionIntegree(idOutputStream);
			}
			finally
			{
				vrEcritureOutputStream.unlock();
			}
		}
		try
		{
			outputStream.close();
		}
		catch (Exception ex)
		{
			/* Ne rien faire */
		}
		sessionComm.oseFinOutputStream(this);
	}
	
	public int getIdOutputStream()
	{
		return idOutputStream;
	}
}
